D:\a\tools.proto\tools.proto\compiler\src\gen\rust\util.rs
Line | Count | Source |
1 | | // Copyright (c) 2024, BlockProject 3D |
2 | | // |
3 | | // All rights reserved. |
4 | | // |
5 | | // Redistribution and use in source and binary forms, with or without modification, |
6 | | // are permitted provided that the following conditions are met: |
7 | | // |
8 | | // * Redistributions of source code must retain the above copyright notice, |
9 | | // this list of conditions and the following disclaimer. |
10 | | // * Redistributions in binary form must reproduce the above copyright notice, |
11 | | // this list of conditions and the following disclaimer in the documentation |
12 | | // and/or other materials provided with the distribution. |
13 | | // * Neither the name of BlockProject 3D nor the names of its contributors |
14 | | // may be used to endorse or promote products derived from this software |
15 | | // without specific prior written permission. |
16 | | // |
17 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
18 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
19 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
20 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
21 | | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
22 | | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
23 | | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
24 | | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
25 | | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
26 | | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
27 | | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | | |
29 | | use crate::compiler::message::{Field, FieldType, Message}; |
30 | | use crate::compiler::structure::FixedFieldType; |
31 | | use crate::compiler::util::types::TypeMapper; |
32 | | use crate::gen::base::map::TypePathMapper; |
33 | | use crate::gen::template::Template; |
34 | | use crate::model::protocol::Endianness; |
35 | | use itertools::Itertools; |
36 | | use std::borrow::Cow; |
37 | | |
38 | | macro_rules! gen_value_type { |
39 | | ($prefix: literal, $ty: expr, $suffix: literal) => { |
40 | | match $ty { |
41 | | FixedFieldType::Int8 => concat!($prefix, "i8", $suffix), |
42 | | FixedFieldType::Int16 => concat!($prefix, "i16", $suffix), |
43 | | FixedFieldType::Int32 => concat!($prefix, "i32", $suffix), |
44 | | FixedFieldType::Int64 => concat!($prefix, "i64", $suffix), |
45 | | FixedFieldType::UInt8 => concat!($prefix, "u8", $suffix), |
46 | | FixedFieldType::UInt16 => concat!($prefix, "u16", $suffix), |
47 | | FixedFieldType::UInt32 => concat!($prefix, "u32", $suffix), |
48 | | FixedFieldType::UInt64 => concat!($prefix, "u64", $suffix), |
49 | | FixedFieldType::Float32 => concat!($prefix, "f32", $suffix), |
50 | | FixedFieldType::Float64 => concat!($prefix, "f64", $suffix), |
51 | | FixedFieldType::Bool => concat!($prefix, "bool", $suffix), |
52 | | } |
53 | | }; |
54 | | } |
55 | | |
56 | | pub struct Generic<'a> { |
57 | | pub name: Cow<'a, str>, |
58 | | pub default: Option<Cow<'a, str>>, |
59 | | } |
60 | | |
61 | | pub struct Generics<T> { |
62 | | lifetime: bool, |
63 | | data: T, |
64 | | } |
65 | | |
66 | | impl<T> Generics<T> { |
67 | 86 | pub fn new(lifetime: bool, data: T) -> Self { |
68 | 86 | Self { |
69 | 86 | lifetime, |
70 | 86 | data |
71 | 86 | } |
72 | 86 | } |
73 | | } |
74 | | |
75 | 86 | fn _to_string<'a>(mut generics: impl Iterator<Item=Cow<'a, str>>, lifetime: bool) -> Cow<'a, str>{ |
76 | 86 | if let Some(value12 ) = generics.next() { Branch (76:12): [True: 4, False: 24]
Branch (76:12): [True: 8, False: 50]
Branch (76:12): [Folded - Ignored]
|
77 | 12 | let str = generics.join(", "); |
78 | 12 | match (str.is_empty(), lifetime) { |
79 | 0 | (true, false) => format!("<{}>", value).into(), |
80 | 0 | (false, false) => format!("<{}, {}>", value, str).into(), |
81 | 12 | (true, true) => format!("<'a, {}>", value).into(), |
82 | 0 | (false, true) => format!("<'a, {}, {}>", value, str).into(), |
83 | | } |
84 | 74 | } else if lifetime { Branch (84:15): [True: 24, False: 0]
Branch (84:15): [True: 41, False: 9]
Branch (84:15): [Folded - Ignored]
|
85 | 65 | Cow::Borrowed("<'a>") |
86 | | } else { |
87 | 9 | Cow::Borrowed("") |
88 | | } |
89 | 86 | } |
90 | | |
91 | | impl<'a, T: Iterator<Item = Generic<'a>>> Generics<T> { |
92 | 58 | pub fn to_string(self) -> Cow<'a, str> { |
93 | 58 | let generics = self.data.map(|v| match &v.default8 { |
94 | 0 | None => v.name, |
95 | 8 | Some(_) => v.name, |
96 | 58 | }8 ); |
97 | 58 | _to_string(generics, self.lifetime) |
98 | 58 | } |
99 | | |
100 | 28 | pub fn to_string_with_defaults(self) -> Cow<'a, str> { |
101 | 28 | let generics = self.data.map(|v| match &v.default4 { |
102 | 0 | None => v.name, |
103 | 4 | Some(v1) => format!("{}={}", v.name, v1).into(), |
104 | 28 | }4 ); |
105 | 28 | _to_string(generics, self.lifetime) |
106 | 28 | } |
107 | | } |
108 | | |
109 | | pub struct RustUtils; |
110 | | |
111 | | impl RustUtils { |
112 | 86 | fn _gen_generics<'a, T: TypeMapper>(msg: &'a Message, type_path_map: &'a TypePathMapper<T>, has_lifetime: bool) -> Generics<impl Iterator<Item = Generic<'a>>> { |
113 | 153 | let unions = msg.fields.iter().filter_map(|v| match &v.ty { |
114 | 12 | FieldType::Union(u) => Some(Generic { |
115 | 12 | name: format!("T{}", v.name).into(), |
116 | 12 | default: Some(format!("{}<'a>", type_path_map.get(&u.r)).into()), |
117 | 12 | }), |
118 | 141 | _ => None, |
119 | 153 | }); |
120 | 86 | Generics::new(has_lifetime, unions) |
121 | 86 | } |
122 | | |
123 | 28 | pub fn get_generics_for_write<'a, T: TypeMapper>( |
124 | 28 | msg: &'a Message, |
125 | 28 | type_path_map: &'a TypePathMapper<T>, |
126 | 28 | ) -> Generics<impl Iterator<Item = Generic<'a>>> { |
127 | 48 | let has_lifetime = msg.fields.iter().any(|v| { |
128 | 29 | matches!( |
129 | 48 | v.ty, |
130 | | FieldType::FixedContainer(_) |
131 | | | FieldType::Union(_) |
132 | | | FieldType::Container(_) |
133 | | | FieldType::SizedContainer(_) |
134 | | ) |
135 | 48 | }); |
136 | 28 | Self::_gen_generics(msg, type_path_map, has_lifetime) |
137 | 28 | } |
138 | | |
139 | 58 | pub fn get_generics<'a, T: TypeMapper>( |
140 | 58 | msg: &'a Message, |
141 | 58 | type_path_map: &'a TypePathMapper<T>, |
142 | 58 | ) -> Generics<impl Iterator<Item = Generic<'a>>> { |
143 | 58 | let has_lifetime = msg.fields.iter().any(|v| { |
144 | 0 | matches!( |
145 | 58 | v.ty, |
146 | | FieldType::Ref(_) |
147 | | | FieldType::Buffer |
148 | | | FieldType::SizedBuffer(_) |
149 | | | FieldType::FixedContainer(_) |
150 | | | FieldType::Union(_) |
151 | | | FieldType::Container(_) |
152 | | | FieldType::SizedContainer(_) |
153 | | | FieldType::Payload |
154 | | ) |
155 | 58 | }); |
156 | 58 | Self::_gen_generics(msg, type_path_map, has_lifetime) |
157 | 58 | } |
158 | | } |
159 | | |
160 | | impl crate::gen::base::structure::Utilities for RustUtils { |
161 | 1.21k | fn get_field_type(field_type: FixedFieldType) -> &'static str { |
162 | 1.21k | gen_value_type!96 ("", field_type, "") |
163 | 1.21k | } |
164 | | |
165 | 198 | fn get_fragment_name(field: &crate::compiler::structure::Field) -> &'static str { |
166 | 198 | //TODO: Check if unwrap is safe |
167 | 198 | let raw_field_type = field.ty.as_fixed().unwrap().bits_type; |
168 | 198 | let raw_field_byte_size = raw_field_type.get_byte_size(); |
169 | 198 | match raw_field_byte_size != field.loc.byte_size { |
170 | 12 | true => "unaligned", |
171 | 186 | false => "aligned", |
172 | | } |
173 | 198 | } |
174 | | |
175 | 0 | fn get_fragment_name_mut(field: &crate::compiler::structure::Field) -> &'static str { |
176 | 0 | //TODO: Check if unwrap is safe |
177 | 0 | let raw_field_type = field.ty.as_fixed().unwrap().bits_type; |
178 | 0 | let raw_field_byte_size = raw_field_type.get_byte_size(); |
179 | 0 | match raw_field_byte_size != field.loc.byte_size { |
180 | 0 | true => "unaligned", |
181 | 0 | false => "aligned", |
182 | | } |
183 | 0 | } |
184 | | |
185 | 64 | fn get_bit_codec_inline(endianness: Endianness) -> &'static str { |
186 | 64 | match endianness { |
187 | 48 | Endianness::Little => "<bp3d_proto::codec::BitCodecLE as bp3d_proto::codec::BitCodec>", |
188 | 16 | Endianness::Big => "<bp3d_proto::codec::BitCodecBE as bp3d_proto::codec::BitCodec>", |
189 | | } |
190 | 64 | } |
191 | | |
192 | 134 | fn get_byte_codec_inline(endianness: Endianness) -> &'static str { |
193 | 134 | match endianness { |
194 | 134 | Endianness::Little => "<bp3d_proto::codec::ByteCodecLE as bp3d_proto::codec::ByteCodec>", |
195 | 0 | Endianness::Big => "<bp3d_proto::codec::ByteCodecBE as bp3d_proto::codec::ByteCodec>", |
196 | | } |
197 | 134 | } |
198 | | |
199 | 12 | fn get_byte_codec(endianness: Endianness) -> &'static str { |
200 | 12 | match endianness { |
201 | 12 | Endianness::Little => "bp3d_proto::codec::ByteCodecLE", |
202 | 0 | Endianness::Big => "bp3d_proto::codec::ByteCodecBE", |
203 | | } |
204 | 12 | } |
205 | | } |
206 | | |
207 | | impl crate::gen::base::message::Utilities for RustUtils { |
208 | 102 | fn get_value_type(endianness: Endianness, ty: FixedFieldType) -> &'static str { |
209 | 102 | match endianness { |
210 | 102 | Endianness::Little => gen_value_type!0 ("bp3d_proto::message::util::ValueLE<", ty, ">"), |
211 | 0 | Endianness::Big => gen_value_type!("bp3d_proto::message::util::ValueBE<", ty, ">"), |
212 | | } |
213 | 102 | } |
214 | | |
215 | 10 | fn get_value_type_inline(endianness: Endianness, ty: FixedFieldType) -> &'static str { |
216 | 10 | match endianness { |
217 | 10 | Endianness::Little => gen_value_type!0 ("bp3d_proto::message::util::ValueLE::<", ty, ">"), |
218 | 0 | Endianness::Big => gen_value_type!("bp3d_proto::message::util::ValueBE::<", ty, ">"), |
219 | | } |
220 | 10 | } |
221 | | |
222 | 9 | fn gen_struct_ref_type(type_name: &str) -> String { |
223 | 9 | format!("{}<&'a [u8]>", type_name) |
224 | 9 | } |
225 | | |
226 | 2 | fn gen_message_ref_type(type_name: &str) -> String { |
227 | 2 | format!("{}<'a>", type_name) |
228 | 2 | } |
229 | | } |
230 | | |
231 | 121 | pub fn gen_where_clause<T: TypeMapper>( |
232 | 121 | template: &Template, |
233 | 121 | field: &Field, |
234 | 121 | type_path_map: &TypePathMapper<T>, |
235 | 121 | function: &str, |
236 | 121 | ) -> String { |
237 | 121 | match &field.ty { |
238 | 13 | FieldType::Union(v) => template |
239 | 13 | .scope() |
240 | 13 | .var("name", &field.name) |
241 | 13 | .var("type_name", type_path_map.get(&v.r)) |
242 | 13 | .var("discriminant_type", type_path_map.get(&v.r.discriminant.root)) |
243 | 13 | .render(function, &["where"]) |
244 | 13 | .unwrap(), |
245 | 108 | _ => "".into(), |
246 | | } |
247 | 121 | } |